﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public enum RoleState
{
    Start,
    None,
    Run,
    JumpUp,
    JumpDown,
    Down,
    Gliding, // 滑翔
    Fly, // 飞行
    ReBound, // 踩怪反弹
}

// 人形角色状态基类
public class HumanState : State
{
    public RoleState SType { get; set; }
    public float Param = -1f; // 自定义参数

    public Action DownKeyDownCallback;
    public Action DownKeyUpCallback;
    public Action JumpKeyDownCallback;
    public Action JumpKeyUpCallback;

    // 请求跳转到新状态
    // Action<newState, allow?>
    public Func<RoleState, bool> RequestChangeState;

    public HumanState()
    {
        // 默认可以强制跳转
        RequestChangeState = (a) => true;
    }
}

public class HumanStateMachine : StateMachine
{
    public HumanState CurState { get { return _curState as HumanState; } }

}

public class HumanStateMgr
{
    HumanCtrl _owner;

    HumanStateMachine _machine;
    HumanState _startState = new HumanState(); // 开始，只进一次
    HumanState _noneState = new HumanState();      // 所有状态跳出，都回到这个状态
    HumanState _runState = new HumanState();
    HumanState _downState = new HumanState();
    HumanState _jumpUpState = new HumanState();
    HumanState _jumpDownState = new HumanState();
    HumanState _glidingState = new HumanState();   // 滑翔
    HumanState _flyState = new HumanState();
    HumanState _reboundState = new HumanState(); // 踩怪反弹

    TimerMgr.Timer _engine;

    // n段跳
    private const int MaxJumpCount = 2;

    // 已连跳次数
    private int _curJumpCount = 0;

    // 被怪物杀死，回调
    private Action _beKilledCallback;

    private bool isDownPressed = false;
    private bool isJumpPressed = false;

    // 是否在地面上(应使用物理检测)
    public bool IsGround { get; private set; }
    public bool IsFlyState { get { return CurState == RoleState.Fly; } }
    public bool IsGildingState { get { return CurState == RoleState.Gliding; } }
    public bool IsJumpDownState { get { return CurState == RoleState.JumpDown; } }

    public RoleState CurState { get { return _machine.CurState.SType; } }

    public void Init(HumanCtrl owner, Action beKilledCallback)
    {
        _curJumpCount = 0;

        _owner = owner;
        _beKilledCallback = beKilledCallback;

        _initState();

        _machine = new HumanStateMachine();
        _machine.ChangeState(_startState);

        _engine = TimerMgr.Instance.CreateTimer(0, -1, loop);
    }

    public void Release()
    {
        _engine.Stop();
    }

    public void Start()
    {
        _engine.Start();
    }

    private void _initState()
    {
        // 
        _startState.SType = RoleState.Start;
        _noneState.EnterCallback = onStartEnter;

        // none
        _noneState.SType = RoleState.None;
        _noneState.EnterCallback = onNoneEnter;

        // run
        _runState.SType = RoleState.Run;
        _runState.EnterCallback = onRunEnter;
        _runState.DownKeyDownCallback = onDownKeyDownInRun;
        _runState.JumpKeyDownCallback = onJumpKeyDownInRun;

        // down
        _downState.SType = RoleState.Down;
        _downState.EnterCallback = onDownEnter;
        _downState.LoopCallback = onDownLoop;
        _downState.ExitCallback = onDownExit;
        _downState.DownKeyUpCallback = onDownKeyUpInDown;
        _downState.JumpKeyDownCallback = onJumpKeyDownInDown;

        // jumpUp
        _jumpUpState.SType = RoleState.JumpUp;
        _jumpUpState.EnterCallback = onJumpUpEnter;
        _jumpUpState.JumpKeyDownCallback = onJumpKeyDownInJumpUp;

        // jumpDown
        _jumpDownState.SType = RoleState.JumpDown;
        _jumpDownState.EnterCallback = onJumpDownEnter;
        _jumpDownState.LoopCallback = onJumpDownLoop;
        _jumpDownState.JumpKeyDownCallback = onJumpKeyDownInJumpDown;

        // gliding
        _glidingState.SType = RoleState.Gliding;
        _glidingState.EnterCallback = onGlidingEnter;
        _glidingState.LoopCallback = onGlidingLoop;
        _glidingState.ExitCallback = onGlidingExit;
        _glidingState.JumpKeyUpCallback = onJumpKeyUpInGliding;

        // fly
        _flyState.SType = RoleState.Fly;
        _flyState.EnterCallback = onFlyEnter;
        _flyState.ExitCallback = onFlyExit;

        // rebound
        _reboundState.SType = RoleState.ReBound;
        _reboundState.EnterCallback = onReboundEnter;
        _reboundState.JumpKeyDownCallback = onJumpKeyDownInRebound;
    }

    #region Fly
    internal void OnFly(bool bFly, float speedUpValue)
    {
        // 退出飞行
        if (bFly == false )
        {
            // 在非飞行状态下，请求退出
            if (!IsFlyState) { return; }

            _machine.ChangeState(_jumpUpState);
            return;
        }

        // 开始飞行
        if (_machine.CurState.RequestChangeState == null) { return; }

        if (!_machine.CurState.RequestChangeState(RoleState.Fly)) { return; }

        _flyState.Param = speedUpValue;
        _machine.ChangeState(_flyState);
    }

    private void onFlyExit()
    {
        _owner.SetFlySpeed(false);
    }

    private void onFlyEnter()
    {
        resetJump();
        _owner.PlayAni(_flyState.SType);
        _owner.SetFlySpeed(true, _flyState.Param);
    }
    #endregion Fly

    #region Rebound
    private void onJumpKeyDownInRebound()
    {
        jumpKeyDownInAir();
    }

    private void onReboundEnter()
    {
        resetJump();
        _owner.JumpOnce(_reboundState.SType, _owner.DefaultAttackOverSpeed);
        //_owner.PlayAni(_reboundState.SType);
    }
    #endregion Rebound

    #region Gliding
    // gliding状态，抬起jump键
    private void onJumpKeyUpInGliding()
    {
        exitCurState();
    }

    private void onGlidingExit()
    {
        //Debug.Log("onGlidingExit");
        _owner.ResetGravity();
    }

    private void onGlidingLoop()
    {
        if (IsGround) { exitCurState(); }
    }

    private void onGlidingEnter()
    {
        //Debug.Log("onGlidingEnter");
        // 滑翔速度
        _owner.SetVSpeedForGliding();
        _owner.PlayAni(_glidingState.SType);
    }
    #endregion Gliding

    #region JumpDown
    // jumpDown状态，按下jump键
    private void onJumpKeyDownInJumpDown()
    {
        jumpKeyDownInAir();
    }

    private void onJumpDownLoop()
    {
        if (IsGround) { exitCurState(); }
    }

    private void onJumpDownEnter()
    {
        _owner.PlayAni(_jumpDownState.SType);
    }
    #endregion JumpDown

    #region JumpUp
    // jumpUp状态，jump键按下
    private void onJumpKeyDownInJumpUp()
    {
        jumpKeyDownInAir();
    }

    // 在空中时，再按jump键
    private void jumpKeyDownInAir()
    {
        // 多段跳
        if (_curJumpCount < MaxJumpCount)
        {
            // jump状态下，也强制再跳一次
            _machine.ChangeState(_jumpUpState, true);
            return;
        }

        // 滑翔
        _machine.ChangeState(_glidingState);
    }

    private void resetJump()
    {
        _curJumpCount = 0;
    }

    private void onJumpUpEnter()
    {
        _curJumpCount++;

        _owner.JumpOnce(_jumpUpState.SType);
    }
    #endregion JumpUp

    #region Down
    // down状态，jump键按下
    private void onJumpKeyDownInDown()
    {
        _machine.ChangeState(_jumpUpState);
    }

    // down状态，down键抬起
    private void onDownKeyUpInDown()
    {
        // 头顶有碰撞，不能起身
        if (_owner.CheckPlayerTopState())
        {
            return;
        }
        exitCurState();
    }

    private void onDownExit()
    {
        _owner.ResetCollider();
    }

    private void onDownLoop()
    {
        if (isDownPressed) { return; }

        if (!_owner.CheckPlayerTopState())
        {
            _machine.ChangeState(_runState);
        }
    }

    private void onDownEnter()
    {
        resetJump();
        _owner.SetDownCollider();
        _owner.PlayAni(_downState.SType);
    }

    #endregion Down

    #region Run
    // run状态，按下jump键
    private void onJumpKeyDownInRun()
    {
        _machine.ChangeState(_jumpUpState);
    }

    // run状态，按下down键
    private void onDownKeyDownInRun()
    {
        _machine.ChangeState(_downState);
    }

    private void onRunEnter()
    {
        resetJump();
        _owner.PlayAni(_runState.SType);
    }
    #endregion Run

    #region None
    // 负责处理状态结束时的跳转
    private void onNoneEnter()
    {
        IsGround = _owner.CheckPlayerBottomState();

        if (IsGround)
        {
            if (isDownPressed)
            { _machine.ChangeState(_downState); }
            else
            { _machine.ChangeState(_runState); }
        }
        else
        {
            if (!_owner.IsFallingDown)
            {
                //_machine.ChangeState(_jumpUpState);
                _machine.ChangeStateSilence(_jumpUpState);
            }
            else
            {
                _machine.ChangeState(_jumpDownState);
            }
        }
    }

    // 退出当前状态
    private void exitCurState()
    {
        _machine.ChangeState(_noneState);
    }

    private void onStartEnter()
    {
        IsGround = _owner.CheckPlayerBottomState();

        if (IsGround) { _machine.ChangeState(_runState); return; }

        _machine.ChangeState(_jumpDownState);
    }

    #endregion None

    // 全局性的状态检测
    private void globalCheck()
    {
        if (IsFlyState) { return; }

        IsGround = _owner.CheckPlayerBottomState();

        if (IsGround)
        {
            //Debug.Log("Ground");
        }
        else // 检查下落
        {
            // 滑翔状态不检查
            if (IsGildingState) { return; }

            if (_owner.IsFallingDown) { _machine.ChangeState(_jumpDownState); }
        }
    }

    // 踩敌人
    bool bNeedAttackBack = false;
    private void attackEnemy(Enemy enemy)
    {
        enemy.BeAttacked(_owner);
        // 处理一帧同时碰到多个敌人的情况
        delayAttackBack();
        QuickCoroutine.Instance.StartCoroutine(delayAttackBack());
    }

    private IEnumerator delayAttackBack()
    {
        bNeedAttackBack = true;
        yield return new WaitForEndOfFrame();
        // 多个相同协程，只执行一次
        if (bNeedAttackBack == true)
        {
            resetJump();
            _machine.ChangeState(_reboundState);
        }
        bNeedAttackBack = false;
    }

    // 碰到敌人
    internal void OnEnemyEnter(Enemy enemy)
    {
        if (IsJumpDownState)
        {
            attackEnemy(enemy);
        }
        else
        {
            beKilled(enemy);
        }
    }

    // 被杀死
    private void beKilled(Enemy enemy)
    {
        if (_beKilledCallback != null) { _beKilledCallback(); }
    }

    internal void OnJumpKeyUp()
    { isJumpPressed = false; Utils.SafeActionCallback(_machine.CurState.JumpKeyUpCallback); }
    internal void OnJumpKeyDown()
    { isJumpPressed = true; Utils.SafeActionCallback(_machine.CurState.JumpKeyDownCallback); }
    internal void OnDownKeyUp()
    { isDownPressed = false; Utils.SafeActionCallback(_machine.CurState.DownKeyUpCallback); }
    internal void OnDownKeyDown()
    { isDownPressed = true; Utils.SafeActionCallback(_machine.CurState.DownKeyDownCallback); }

    private void loop()
    {
        globalCheck();
        _machine.Loop();

        //Debug.Log(CurState);
    }
}
